package com.meta.nd.service.impl;

import java.util.List;
import com.meta.cache.NdCacheService;
import com.meta.common.CommonInfo;
import com.meta.nd.filter.bo.FilterParamDef;
import com.meta.nd.filter.utils.FilterDefBuilder;
import com.meta.nd.filter.vo.FilterResultVo;
import com.meta.nd.service.ExecuteRuleService;
import com.meta.nd.service.NvFilterService;
import com.meta.nd.util.NodeUtil;
import com.meta.rule.RuleRunContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import com.meta.common.ConstDef;
import com.meta.counter.service.CounterService;
import com.meta.nd.dao.NvDAO;
import com.meta.nd.service.NvService;
import com.meta.nd.vo.ListQueryCondition;
import com.meta.nd.vo.ListQueryResult;
import com.meta.nd.vo.Nd;
import com.meta.nd.vo.Nv;

import javax.annotation.Resource;


@EnableTransactionManagement
@Transactional(rollbackFor = Exception.class)
@Component
public class NvServiceImpl implements NvService {
	
	@Resource
	NvDAO nvDAO;
	
	@Resource
	CounterService counterService;

	@Resource
	NdCacheService ndCacheService;

	@Resource
	ExecuteRuleService executeRuleService;

	@Resource
	NvFilterService nvFilterService;

	private void preSaveProcess(Nv nv) {
		if (nv.getParent()!=null){
			nv.setParentId(nv.getParent().getId());
		}
	}
	
	
	private void preSaveNvsProcess( List<Nv> nvs ) {
		
		if ( nvs.size() == 0 )
			return ;
		
		for(Nv nv : nvs){
			if ( nv.getParent()!=null)
				nv.setParentId(nv.getParent().getId());
		}
	}
	
	

@Override
public long saveNv(CommonInfo commonInfo,Nv nv) {
	RuleRunContext context = new RuleRunContext();
	executeRuleService.executeNvRule(ConstDef.TRANSACTION_TYPE_SAVE, nv, context);
	if ( !context.isSuccess() || !context.isValid())
		throw new RuntimeException("保存实例执行规则有错 ：" + context.getMessageText());
	if ( ConstDef.OPERATION_FLAG_DELETE.equals(nv.getOperationFlag()) ) {
		this.nvDAO.deleteNv(nv.getNd().getNdCode(), nv.getId());
		nv.getChildrenMap().clear();
		return nv.getId();
	}else if ( ConstDef.OPERATION_FLAG_UNCHANGED.equals(nv.getOperationFlag())) {

	}
	else {
		 preSaveProcess(nv);
		 nvDAO.saveNv(nv);
	}
	for ( String name : nv.getChildrenMap().keySet()) {
		List<Nv> childNvs = nv.getChildrenMap().get(name);
		this.internalSaveNvs(commonInfo, childNvs);
	}
	return nv.getId();
}

	@Override
	public void saveNvs(CommonInfo commonInfo, List<Nv> nvs ){
		RuleRunContext context = new RuleRunContext();
		for( Nv nv : nvs) {
			if(ConstDef.OPERATION_FLAG_DELETE.equals(nv.getOperationFlag()))
				continue;
			executeRuleService.executeNvRule(ConstDef.TRANSACTION_TYPE_SAVE, nv, context);
			if ( !context.isSuccess() || !context.isValid())
				throw new RuntimeException("保存实例执行规则有错 ：" + context.getMessageText());
		}
		this.internalSaveNvs(commonInfo,nvs);
	}

	@Override
	public void internalSaveNvs(CommonInfo commonInfo, List<Nv> nvs ){
		for(int i = nvs.size()-1; i>=0; i--){
			Nv nv = nvs.get(i);
			if (ConstDef.OPERATION_FLAG_DELETE.equals(nv.getOperationFlag())) {
				this.nvDAO.deleteNv(nv.getNd().getNdCode(), nv.getId());
				nvs.remove(nv);
			}
		}
		for(int i =0;i < nvs.size(); i++) {
			Nv nv = nvs.get(i);
			if (ConstDef.OPERATION_FLAG_UNCHANGED.equals(nv.getOperationFlag())) {
			} else {
				preSaveProcess(nv);
				nvDAO.saveNv(nv);
			}
			for (String name : nv.getChildrenMap().keySet()) {
				List<Nv> childNvs = nv.getChildrenMap().get(name);
				this.internalSaveNvs(commonInfo, childNvs);
			}
		}
	}

	@Override
	public Nv getNv(CommonInfo commonInfo,String ndCode, long id){
		return nvDAO.getNv(ndCode,id);
	}

	@Override
	public Nv getSingleNvWithoutFv(CommonInfo commonInfo, String ndCode, long id){
		return nvDAO.getSingleNvWithoutFv(ndCode,id);
	}
	
	@Override
	public Nv getNvByCode(CommonInfo commonInfo,String code, String name, String ndCode ) {
		Nv nv =  nvDAO.getSingleNvByCode(code, name, ndCode);
		nv = nvDAO.getNv(nv.getNd().getNdCode(),nv.getId());
		return nv;
	}




	@Override
	public Object getFvByExpression( String expression, String ndCode){
		Nd nd = this.ndCacheService.getNd(ndCode);
		String dbMapCode = nd.getDbMapCode();
		return this.nvDAO.getFvByExpression(expression,dbMapCode);
	}

	@Override
	public Nv getParentNvCodeAndNdCode(CommonInfo commonInfo,String code, String codeFdName, String ndCode){
		Nd nd = this.ndCacheService.getNd(ndCode);
		Nd parentNd = nd.getParent();
		if ( parentNd == null){
			throw new RuntimeException(String.format("nd代码为:%s没有父代Nd!", ndCode));
		}
		return getNvByCode(commonInfo,code,codeFdName,parentNd.getNdCode());
	}
	@Override
	public long getParentNvIdCodeAndNdCode(CommonInfo commonInfo,String code, String codeFdName, String ndCode){
		Nd nd = this.ndCacheService.getNd(ndCode);
		Nd parentNd = nd.getParent();
		if ( parentNd == null){
			throw new RuntimeException(String.format("nd代码为:%s没有父代Nd!", ndCode));
		}
		Nv nv = nvDAO.getRootNvByCode(code, codeFdName, parentNd.getNdCode());
		return nv.getId();
	}

	@Override
	public Nv copyNvById(CommonInfo commonInfo,String ndCode, long id){
		Nv nv = this.getNv(commonInfo,ndCode,id);
		this.clearIdForNew(nv);
		return nv;
	}

	@Override
	public Nv copyNv( CommonInfo commonInfo,Nv nv){
		this.clearIdForNew(nv);
		return nv;
	}

	private void clearIdForNew( Nv nv ){
		long id = counterService.nextNegativeId();
		nv.setId(id);
		nv.setParentId(0L);
		nv.setOperationFlag(ConstDef.OPERATION_FLAG_NEW);
		for( List<Nv> childNvs : nv.getChildrenMap().values()){
			for( Nv childNv : childNvs)
				clearIdForNew(childNv);
		}
	}


	@Override
	public Nv initNv( CommonInfo commonInfo,String ndCode){
		Nd nd = this.ndCacheService.getNd(ndCode);
		Nv nv = NodeUtil.nd2Nv(nd);
		RuleRunContext context = new RuleRunContext();
		executeRuleService.executeNvRule(ConstDef.TRANSACTION_TYPE_INIT,nv,context);
		if (!context.isSuccess() || !context.isValid())
			throw new RuntimeException("创建实例失败:" + context.getMessageText());
		long id = counterService.nextNegativeId();
		nv.setId(id);
		nv.setOperationFlag(ConstDef.OPERATION_FLAG_NEW);
		return nv;
	}

	@Override
	public int deleteNv(CommonInfo commonInfo,String ndCode, long id){
		return this.nvDAO.deleteNv(ndCode,id);
	}

	@Override
	public int deleteNvs(CommonInfo commonInfo,String ndCode, List<Long> ids){
		int count = 0;
		for( int i= 0; i < ids.size(); i++) {
			count += this.nvDAO.deleteNv(ndCode, ids.get(i));
		}
		return count;
	}
	
	@Override
	public ListQueryResult<Nv> filterNvs(CommonInfo commonInfo,ListQueryCondition condition ) {
		return this.nvDAO.filterNvs(condition);
	}

	@Override
	@Transactional
	public void resetId(CommonInfo commonInfo,String ndCode){
		Nd nd = ndCacheService.getNd(ndCode);
		FilterDefBuilder builder = FilterDefBuilder.createBuilder(nd,nd.getNdCode(),nd.getNdCode(),nd.getNdCode());
		builder.addResultFd(nd.getNdName(),ConstDef.FD_NAME_ID,null);
		builder.addResultFd(nd.getNdName(),ConstDef.FD_NAME_META_ND_CODE,null);
		if ( nd.isCursive() )
			builder.addFilterFd(nd.getNdName(),ConstDef.FD_NAME_PARENT_ID,null,ConstDef.LOGIC_OPERATION_EQUAL,0L);
		FilterParamDef paramDef = builder.getFilterParamDef();
		FilterResultVo filterResultVo = this.nvFilterService.filterNvsByParamDef(CommonInfo.getDefault(),paramDef);
		filterResultVo.getNvs().forEach(nv->{
			Nv wholeNv = this.getNv(CommonInfo.getDefault(),nv.getActualNdCode(),nv.getId());
			this.deleteNv(CommonInfo.getDefault(),nv.getActualNdCode(),nv.getId());
			this.clearIdForNew(wholeNv);
			this.saveNv(CommonInfo.getDefault(),wholeNv);
		});
	}
}
